#include"App.h"
#include"Game.h"
#include"Debug.h"
#include"ResourceManger.h"

#include<iostream>
#include<Windows.h>
#include<windowsx.h>
#include<thirdparty\glfw3.h>

#include"lowlevel\Font.h"
namespace Craft{


App::App(int w, int h,bool isFull):
		m_width(w),
		m_height(h)
{
	// init glfw
	Debug::log("init the glfw");
	glfwInit();

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

	// create a window
	pMonitor = glfwGetPrimaryMonitor();
	window = glfwCreateWindow(m_width, m_height, "BallBoom", isFull ? pMonitor : nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create window" << std::endl;
		glfwTerminate();
		exit(-1);
	}
	// move the window to center of screen
	int win_posX = (glfwGetVideoMode(pMonitor)->width - SCREEN_WIDTH)  * 0.5f;
	int win_posY = (glfwGetVideoMode(pMonitor)->height - SCREEN_HEIGHT) * 0.5f;

	glfwSetWindowPos(window, win_posX, win_posY);
	glfwMakeContextCurrent(window);

	glfwSetKeyCallback(window,key_callback);
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);	// shadow the cursor
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetMouseButtonCallback(window, mouse_button_callback);

	// glew
	Debug::log("init the glew");
	glewExperimental = GL_TRUE;
	glewInit();

	glViewport(0, 0, m_width, m_height);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// init game world
	Debug::log("init the world");
	game = std::unique_ptr<Game>(new Game());
	game->init();
	
}

App::~App()
{
	ResourceManger::clear();
	glfwTerminate();
}

void App::run()
{

	GLdouble  OPTIMAL_TIME = 1.0f / 60.0f;

	GLdouble  last_frame_date = glfwGetTime();
	GLdouble  accumulator = 0.0f;
	GLdouble  time_dropped = 0.0f;

	GLuint   tmp_fps = 0;
	GLuint   fps = 0;
	GLdouble  fps_last_time = glfwGetTime();

	while (!glfwWindowShouldClose(window))
	{

		GLdouble current_frame = glfwGetTime() - time_dropped;
		GLdouble detla_time = current_frame - last_frame_date;
		last_frame_date = current_frame;
		accumulator += detla_time;

		if (accumulator >= 0.2f)
		{
			time_dropped += accumulator - OPTIMAL_TIME;
			accumulator = OPTIMAL_TIME;
			last_frame_date = glfwGetTime() - time_dropped;
		}


		if (glfwGetTime() - fps_last_time >= 1.0f)
		{
			fps = tmp_fps;
			tmp_fps = 0;
			fps_last_time = current_frame;
			std::cout << fps << std::endl;
			fps = 0;
		}

		// 1.check input ? InputManger must get  input events 
		glfwPollEvents();
		check_input();
		game->notify_input(detla_time);
		

		int num_updates = 0;
		while (accumulator >= OPTIMAL_TIME &&
			num_updates < 10 && !glfwWindowShouldClose(window))
		{
			// 2.update
			tmp_fps++;
			step(detla_time);
			accumulator -= OPTIMAL_TIME;
			++num_updates;
		}

		// 3.render
		if (num_updates > 0)
		{
			glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			render();
			
			glfwSwapBuffers(window);
		}

		// 4.if have time,save the cpu cycle
		detla_time = glfwGetTime() - time_dropped - last_frame_date;
		if (detla_time < OPTIMAL_TIME)
		{
			SleepEx(OPTIMAL_TIME - detla_time, false);
		}

	}
}



void App::check_input()
{
}


void App::step(double deltaTime)
{
	game->update(deltaTime);
}


void App::render()
{
	game->draw();
}



}